package engine;


import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Picture;
import android.graphics.drawable.PictureDrawable;
import android.util.Log;
import com.tetris.project.Game;
import com.tetris.project.GameOver;
import com.tetris.project.Shr_Res;
import framework.Physics;
import framework.ScreenObject;
import framework.interfaces.Movable;
import framework.interfaces.Rotable;
import framework.interfaces.Updatable;
import framework.utils.GlobalManager;

public class Piece extends ScreenObject implements Rotable, Movable, Updatable{

	public static char[][] mPieceCollection;
	public static int  mCurrent;
	int mColor;
	int mBoardX, mBoardY;
	static final int NORMAL = 0;
	static final int R90 = 1;
	static final int R180 = 2;
	static final int R270 = 3;
	public static boolean isConstructPieceCallExecuting = false;
	public static boolean isRotateRunning = false;
	boolean firstTime = true;
	private int mResource;
	public PictureDrawable mPictureDrawable;
	public Picture mPiecePicture;
	public Board mBoard;

	public Piece(int x, int y, char[][] pieceCollection, Board board){
		super(x, y, null);
		resetImageCoordinates();
		mPieceCollection = pieceCollection;
		mCurrent = NORMAL;
		selectColor(TetrisPieceManager.getRandomNumber());
		mBoard = board;
		mPiecePicture = new Picture();
		mPictureDrawable =  new PictureDrawable(mPiecePicture);
		constructPiecePicture(); // Construct the first Piece of the game.
		Log.d(Shr_Res.TAG, "mX calculated in Piece Constructor = " + mX);
		Log.d(Shr_Res.TAG, "mY calculated in Piece Constructor = " + mY);
		Log.d(Shr_Res.TAG, "mWidth initial value in Piece constructor = " + mWidth);
		Log.d(Shr_Res.TAG, "mHeight initial value in Piece constructor = " + mHeight);
	}

	public char[] getPiece()
	{
		return mPieceCollection[mCurrent];
	}

	public char[] getPiece(int p)
	{
		return mPieceCollection[p];
	}
	
	public PictureDrawable getPiecePic()
	{
		return mPictureDrawable;
	}

	public int getBoardX()
	{
		return mBoardX;
	}

	public int getBoardY()
	{
		return mBoardY;
	}

	protected void selectColor(int color)
	{
		//Select the proper brick to construct the piece depending on the color
		switch(color)
		{
			case 0://Color.BLUE:
				mResource = GlobalManager.mDrawableResources[0];
				break;
			case 1://Color.RED:
				mResource = GlobalManager.mDrawableResources[2];
				break;
			case 2://Color.GREEN:
				mResource = GlobalManager.mDrawableResources[1];
				break;
			case 3://Color.YELLOW:
				mResource = GlobalManager.mDrawableResources[3];
				break;
			case 4://Color.PURPLE:
				mResource = GlobalManager.mDrawableResources[4];
				break;
			default:
				mResource = GlobalManager.mDrawableResources[0];
		}
		setImage(GlobalManager.GlobalContext.getResources().getDrawable(mResource));
	}

	@Override
	public synchronized void draw(Canvas c) {
		synchronized(mPictureDrawable) {
			if (TetrisPieceManager.next != 6) {
				mPictureDrawable.setAlpha(0);
				mPictureDrawable.setBounds(mX, mY, mX + (TetrisPieceManager.GRID_RESOLUTION * mWidth),
					mY + (TetrisPieceManager.GRID_RESOLUTION * mHeight));
				mPictureDrawable.draw(c);
			} else {
				if (Piece.mCurrent == 0 || Piece.mCurrent == 2) {
					mPictureDrawable.setAlpha(0);
					mPictureDrawable.setBounds(mX, mY, mX + mWidth, (mY + mHeight) * 4);
					mPictureDrawable.draw(c);
				} else {
					mPictureDrawable.setAlpha(0);
					mPictureDrawable.setBounds(mX, mY, (mX + mWidth) * 4, mY + mHeight);
					mPictureDrawable.draw(c);
				}
			}
			//Log.d("Physics", "Board X "+mBoardX);
			//Log.d("Physics", "Board Y "+mBoardY);
		}
	}

	@Override
	public synchronized void rotate(Direction direction) {
		isRotateRunning = true;
		Log.d(Shr_Res.TAG, "Current Piece: =" + TetrisPieceManager.next);

		int x, y,
			yt = getBoardY(),
			xt = getBoardX(),
			next = (mCurrent == 3) ? 0 : (mCurrent + 1);
		char[] p = getPiece(next);

		if (TetrisPieceManager.next != 0 && TetrisPieceManager.next != 6) {

			if (xt >= 0 && xt < (Board.BOARD_COLS - 2)) {
				for(int i = 0; i < TetrisPieceManager.NUMBER_BLOCKS_PER_PIECE; i++) {
					Log.d(Shr_Res.TAG, "bx = " + xt + "by = " + yt);
					y = (((int)p[i]) / TetrisPieceManager.GRID_RESOLUTION);
					x = (((int)p[i]) % TetrisPieceManager.GRID_RESOLUTION);
					Log.d(Shr_Res.TAG, "mBoard[" + (yt + y) + "]" + "[" + (xt + x)+ "]");

					if (mBoard.getBoard()[yt + y][xt + x] != 0) {
						isRotateRunning = false;
						return;
					};
				}
			} else {
				if (xt == -1) {
					if (isPieceRotable()) {
					} else {
						isRotateRunning = false;
						return;
					}
					//Log.d(Shr_Res.TAG, "mBoardX From ROTATE="+mBoardX);
				} else if (xt == (Board.BOARD_COLS -2)) {
					if (isPieceRotable()) {
					} else {
						isRotateRunning = false;
						return;
					}
				} else {
					isRotateRunning = false;
					return;
				}
			}

			dRotate();
			Log.d(Shr_Res.TAG, "mBoardX ="+mBoardX);
		}

		if (TetrisPieceManager.next == 6) {
			Log.d(Shr_Res.TAG, "Checking if |/-- can be rotated");
			if (Piece.mCurrent == 0 || Piece.mCurrent == 2) {
				if (checkRotable(true)) {
					dRotate();
				}
			} else if (checkRotable(false)) {
				dRotate();
			}
		}
		isRotateRunning = false;
	}
	
	private void dRotate()
	{
		while(isConstructPieceCallExecuting) {}
		mCurrent = (mCurrent != R270) ? ++mCurrent : NORMAL;
		constructPiecePicture();
	}
	
	public boolean isPieceRotable()
	{
		int x, y,
			xt = getBoardX(),
			yt = getBoardY(),
			next = (mCurrent == 3) ? 0 : (mCurrent + 1);
			char[] p = getPiece(next);
		
		if (xt == -1) {
			++xt;
		} else {
			--xt;
		}

		for(int i = 0; i < TetrisPieceManager.NUMBER_BLOCKS_PER_PIECE; i++) {
			y = (((int)p[i]) / TetrisPieceManager.GRID_RESOLUTION);
			x = (((int)p[i]) % TetrisPieceManager.GRID_RESOLUTION);
			if (mBoard.getBoard()[yt + y][xt + x] != 0)
				return false;
		}

		mBoardX = xt;
		mX = mBoardX * mWidth;
		return true;
	}

	public synchronized boolean checkRotable(boolean type) {
		int xt, yt;
		if (type) { // |
			Log.d(Shr_Res.TAG, "Checking if | can be rotated");

			if (getBoardX() == 0) {
				Log.d(Shr_Res.TAG, "I came here A");
				xt = getBoardX();
				yt = getBoardY();
				for (int i = 1; i < 4; i++) {
					for (int j = 0; j < 4; j++) {
						if (mBoard.getBoard()[yt + j][xt + i] != 0) {
								return false;
						}
					}
				}
				mBoardY++;
				mX = mBoardX * mHeight;
				mY = mBoardY * mWidth;
				return true;
			}

			if (getBoardX() == 1) {
				Log.d(Shr_Res.TAG, "I came here B");
				xt = getBoardX() -1;
				yt = getBoardY();
				for (int i = 0; i < 4; i++) {
					if (i != 1) {
						for (int j = 0; j < 4; j++) {
							if (mBoard.getBoard()[yt + j][xt + i] != 0) {
								return false;
							}
						}
					}
				}
				mBoardX--;
				mBoardY++;
				mX = mBoardX * mHeight;
				mY = mBoardY * mWidth;
				//Log.d(Shr_Res.TAG, "This is X: " + getBoardX() + ", Y: " + getBoardY());
				return true;
			}

			if (getBoardX() == (Board.BOARD_COLS -1)) {
				Log.d(Shr_Res.TAG, "I came here 1");
				xt = getBoardX() - 3;
				yt = getBoardY();
				for (int i = 0; i < 3; i++) {
					for (int j = 0; j < 4; j++) {
						Log.d(Shr_Res.TAG, "Rotate |: mBoard[" + (yt + j) + "]" +
							"[" + (xt + i) + "]");
						if (xt < 0 || mBoard.getBoard()[yt + j][xt + i] != 0) {
							Log.d(Shr_Res.TAG, "It can not be rotated |");
							return false;
						}
					}
				}
				mBoardY++;
				mY = mBoardY * mWidth;
				mBoardX -= 3;
				mX = mBoardX * mHeight;
				return true;
			}

			if (getBoardX() == (Board.BOARD_COLS -2)) {
				Log.d(Shr_Res.TAG, "I came here 2");
				xt = getBoardX() - 2;
				yt = getBoardY();
				for (int i = 0; i < 4; i++) {
					if (i == 2)
						continue;
					for (int j = 0; j < 4; j++) {
						Log.d(Shr_Res.TAG, "Rotate |: mBoard[" + (yt + j) + "]" +
							"[" + (xt + i) + "]");
						if (xt < 0 || mBoard.getBoard()[yt + j][xt + i] != 0) {
							Log.d(Shr_Res.TAG, "It can not be rotated |");
							return false;
						}
					}
				}
				mBoardY++;
				mY = mBoardY * mWidth;
				mBoardX -= 2;
				mX = mBoardX * mHeight;
				return true;
			}

			xt = getBoardX() -1;
			yt = getBoardY();

			for (int i = 0; i < 4; i++) {
				if (i == 1)
					continue;
				for (int j = 0; j < 4; j++) {
					if (i == 0) {
						if ((j == 0 || j ==1) && mBoard.getBoard()[yt + j][xt] != 0)
							return false;
					} else {
						if (j != 0) {
							if (mBoard.getBoard()[yt + j][xt + i] != 0)
								return false;
						}
					}
				}
			}
			mBoardX--;
			mBoardY++;
			mX = mBoardX * mHeight;
			mY = mBoardY * mWidth;
			Log.d(Shr_Res.TAG, "The new Pece (----) will be at: " + "[" + mBoardY + "]"
				+ "[" + mBoardX + "]");
			return true;
		} else { // ----
			yt = getBoardY() - 1;
			xt = getBoardX();

			if (yt < 0)
				return false;
			Log.d(Shr_Res.TAG, "Checking if ------ can be rotated");
			Log.d(Shr_Res.TAG, "Starting Position before analisys: mBoard[" + mBoardY + "]" +
				"[" + mBoardX + "]");
			Log.d(Shr_Res.TAG, "Starting Position for Analisys: mBoard[" + yt + "]" +
				"[" + xt + "]");
			for (int i = 0; i < 4; i++) {
				for (int j = 0; j < 4; j++) {
					Log.d(Shr_Res.TAG, "Rotate ----: mBoard[" + (yt + j) + "]" +
						"[" + (xt + i) + "]");
					if (j == 0 && j == 0 && mBoard.getBoard()[yt][xt] != 0)
						return false;
					if (i == 1 && j != 1 && mBoard.getBoard()[yt + j][xt + i] != 0)
						return false;
					if (i > 1 && j != 0 && mBoard.getBoard()[yt + j][xt + i] != 0)
						return false;
				}
			}
			mBoardX++;
			mBoardY--;
			mX = mBoardX * mHeight;
			mY = mBoardY * mWidth;
			return true;
		}
	}

	@Override
	public synchronized void move(Side side) {
		// TODO Auto-generated method stub
		int turn = 1;
		if(side == Side.LEFT)
			turn  = -1;

		if (TetrisPieceManager.next != 6) {
				// Moving to the left side
			if (turn < 0) {
				if (mBoard.hasCollide(this, Side.LEFT))
					return;
				if (mBoardX == 0
					&& TetrisPieceManager.nextPieceLeft[TetrisPieceManager.next][mCurrent] == 1) {
				} 
				else {
					if ((mBoardX + turn) >= 0) {
					}else{
						return;
					}
				}
			}

			if (turn > 0) {
				// Moving to the right side
				if (mBoard.hasCollide(this, Side.RIGHT))
					return;
				Log.d(Shr_Res.TAG, "Before moving to the right BX = " + mBoardX);
				if ((Board.BOARD_COLS - (mBoardX + TetrisPieceManager.pieceWidth[TetrisPieceManager.next][mCurrent])) == 0) {
					return;
				}
			}
		}

		if (TetrisPieceManager.next == 6) {
			if (side == Side.LEFT) {
				if (mBoard.hasCollide(this, Side.LEFT)) 
					return;
			} else {
				if (mBoard.hasCollide(this, Side.RIGHT))
					return;
			}
		}

		mBoardX += turn;
		mX = mBoardX * mWidth;
		Log.d(Shr_Res.TAG, "mX After moving it to the " + ((turn == 1) ? "Right" : "Left")
			+ " Side: " + mX);
		Log.d(Shr_Res.TAG, "mBoardX After moving it to the " + ((turn == 1) ? "Right" : "Left")
				+ " Side: " + mBoardX);
	}

	protected synchronized void constructPiecePicture()
	{
		/* Need to build the piece with the proper set of images, in the proper order
		 */
		int dX, dY;
		isConstructPieceCallExecuting = true;
		if (TetrisPieceManager.next != 6) {
			Canvas c = mPictureDrawable.getPicture().beginRecording(
				mWidth * TetrisPieceManager.GRID_RESOLUTION,
				mHeight * TetrisPieceManager.GRID_RESOLUTION);
			char currentBlock;
			c.drawColor(Color.TRANSPARENT);
			dX = 0; dY = 0;

			for(int i = 0; i < TetrisPieceManager.NUMBER_BLOCKS_PER_PIECE; i++) {
				currentBlock = (char) (mPieceCollection[mCurrent][i] & TetrisPieceManager.NUMBER_MASK);
				dY =((currentBlock / TetrisPieceManager.GRID_RESOLUTION) * mHeight);
				dX =((currentBlock % TetrisPieceManager.GRID_RESOLUTION) * mWidth);
				mImage.setBounds(dX, dY, dX + mWidth, dY + mHeight);
				mImage.draw(c);
			}
			mPictureDrawable.getPicture().endRecording();
		} else {
			if (mCurrent == 0 || mCurrent == 2) {
				Canvas c = mPictureDrawable.getPicture().beginRecording(
					mWidth * 1,
					mHeight * 4);
				c.drawColor(Color.TRANSPARENT);
				dX = 0; dY = 0;
				for(int i = 0; i < TetrisPieceManager.NUMBER_BLOCKS_PER_PIECE; i++) {
					mImage.setBounds(dX, dY, dX + mWidth, dY + mHeight);
					mImage.draw(c);
					dY += mHeight;
				}
				mPictureDrawable.getPicture().endRecording();
			}else {
				Canvas c = mPictureDrawable.getPicture().beginRecording(
					mWidth * 4,
					mHeight * 1);
				c.drawColor(Color.TRANSPARENT);
				dX = 0; dY = 0;
				for(int i = 0; i < TetrisPieceManager.NUMBER_BLOCKS_PER_PIECE; i++) {
					mImage.setBounds(dX, dY, dX + mWidth, dY + mHeight);
					mImage.draw(c);
					dX += mWidth;
				}
				mPictureDrawable.getPicture().endRecording();
			}
		}
		isConstructPieceCallExecuting = false;
	}

	@Override
	public void update(double value) {
		
		if (firstTime) {
			resetImageCoordinates();
			firstTime = false;
		}
		
		
//		if(Shr_Res.sendDownPiece){
//			mY = mY + (int)value;
//		}else{
			mY = (int)value;
//		}
		mBoardY = mY / mHeight;

		if(mBoard.hasCollide(this, Side.DOWN)) {
			Shr_Res.timeToChangePiece = true;
			if(mY == 0) {
				//Call GameOver
				Game.gameOver = true;
				Intent gameOverIntent = new Intent(GamePlayScene.context, GameOver.class);
				GamePlayScene.context.startActivity(gameOverIntent);
				Log.d(Shr_Res.TAG, "Call GameOver");
			} else {
				//Log.d(Shr_Res.TAG, "There was a collision Down");
				mBoard.insertPiece(this);
				//mPieceCollection  = TetrisPieceManager.getRandomPiece();
				mPieceCollection = NextPiece.getNextPiece();
				//selectColor(TetrisPieceManager.getRandomNumber());
				mImage = NextPiece.getNextPieceBrick();
				setImage(mImage);
				mResource = NextPiece.getNextResource();
				NextPiece.getNewPiece();
				constructPiecePicture();
				resetImageCoordinates();
				Physics.resetPhysics();
				Physics.resetResumedTime();
				Shr_Res.sendDownPiece = false;
			}
		}
	}

	public void resetImageCoordinates(){
		//Sets the piece coordinate to be the center of the game board.
		//Log.d(Shr_Res.TAG, "Resetting Image Coordinates");
		mY = 0;
		mBoardY = 0;
		mX = (Board.BOARD_COLS / 2) * mWidth - mWidth;
		mBoardX = (Board.BOARD_COLS / 2) - 1;
	}

	int getResource() {
		return mResource;
	}

	//Returns the width of a single element that forms the piece
	public int getUnitPieceWidth(){
		return mPictureDrawable.getIntrinsicWidth()/3;
	}

	//Returns the height of a single element that forms the piece
	public int getUnitPieceHeight(){
		return mPictureDrawable.getIntrinsicHeight()/3;
	}
}
